#ifndef __PING_INTERFACE_COMMON_H__
#define __PING_INTERFACE_COMMON_H__

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/uio.h>
#include <sys/poll.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <setjmp.h>

#ifdef CAPABILITIES
#include <sys/prctl.h>
#include <sys/capability.h>
#endif

#ifdef USE_IDN
#include <locale.h>
#include <idna.h>
#endif

#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/types.h>
#include <linux/errqueue.h>

#ifdef ANDROID
#include <linux/icmp.h>
#include <sys/auxv.h>
#endif



#define LYB_DEBUG


#ifdef LYB_DEBUG
extern int errno;
#define FUNCLINE "ping_interface:[%s][%d]: "
#define ERRLINE  "error: (%s)"
//#define __log_debug(fmt, ...) 
#define __log_debug(fmt, ...) printf(FUNCLINE fmt "\n",__func__ , __LINE__ ,##__VA_ARGS__)
#define __log_error(fmt, ...) fprintf(stderr, FUNCLINE ERRLINE  fmt ,__func__ , __LINE__ , strerror(errno) ,##__VA_ARGS__)
#else
#define __log_debug(fmt, ...) 
#define __log_error(fmt, ...) 
#endif


#ifdef USE_BITMAP64
typedef __u64	bitmap_t;
# define BITMAP_SHIFT	6
#else
typedef __u32	bitmap_t;
# define BITMAP_SHIFT	5
#endif

#define	MAX_DUP_CHK	0x10000

struct rcvd_table {
	bitmap_t bitmap[MAX_DUP_CHK / (sizeof(bitmap_t) * 8)];
};

static struct rcvd_table rcvd_tbl;

#define	A(bit)	(rcvd_tbl.bitmap[(bit) >> BITMAP_SHIFT])	/* identify word in array */
#define	B(bit)	(((bitmap_t)1) << ((bit) & ((1 << BITMAP_SHIFT) - 1)))	/* identify bit in word cmsg_len */


#define	DEFDATALEN	(64 - 8)	/* default data length */
#define MINUSERINTERVAL	200		/* Minimal allowed interval for non-root */
#define	MAXWAIT		10		/* max seconds to wait for response */
#define	MAXIPLEN	60
#define	MAXICMPLEN	76
#define MININTERVAL	10		/* Minimal interpacket gap */

#define SCHINT(a)	(((a) <= MININTERVAL) ? MININTERVAL : (a))

#ifndef MSG_CONFIRM
#define MSG_CONFIRM 0
#endif

#if BYTE_ORDER == LITTLE_ENDIAN
# define ODDBYTE(v)	(v)
#elif BYTE_ORDER == BIG_ENDIAN
# define ODDBYTE(v)	((u_short)(v) << 8)qweqwe
#else
# define ODDBYTE(v)	htons((u_short)(v) << 8)xzczxc
#endif


#define MAX_HOSTNAMELEN	NI_MAXHOST


 /* various options */
 //extern int options;
#define	F_FLOOD		0x001
#define	F_INTERVAL	0x002
#define	F_NUMERIC	0x004
#define	F_PINGFILLED	0x008
#define	F_QUIET		0x010
#define	F_RROUTE	0x020
#define	F_SO_DEBUG	0x040
#define	F_SO_DONTROUTE	0x080
#define	F_VERBOSE	0x100
#define	F_TIMESTAMP	0x200
#define	F_FLOWINFO	0x200
#define	F_SOURCEROUTE	0x400
#define	F_TCLASS	0x400
#define	F_FLOOD_POLL	0x800
#define	F_LATENCY	0x1000
#define	F_AUDIBLE	0x2000
#define	F_ADAPTIVE	0x4000
#define	F_STRICTSOURCE	0x8000
#define F_NOLOOP	0x10000
#define F_TTL		0x20000
#define F_MARK		0x40000
#define F_PTIMEOFDAY	0x80000
#define F_OUTSTANDING	0x100000

 struct send_msg{
	 int	 msg_id;
	 char*	 entity;
	 char*	 target;
 };


 struct handle_send_msg{
	 struct send_msg	 	msg;
	 int					socketfd;
 };





 typedef struct connect_msg {
    struct cmsghdr cm;
    struct in_pktinfo ipi;
} st_connect_msg;

 typedef struct handler_packet {
    void* (*handler_func) (void *);
  	void* arg;
} st_handler_packet;

typedef struct status {
	struct timeval 		start_time;
	struct timeval		cur_time;
	volatile int 		exiting;
	long 				ntransmitted;		/* sequence # for outbound packets = #sent */
	int 				deadline;
    int 				nreceived;
	long 				nerrors;
	__u16 				acked;
	int  				pipesize;
	unsigned long 		waittime;
	volatile int 		in_pr_addr;
	jmp_buf 			pr_addr_jmp;
	long long 			tsum;			/* sum of all times, for doing average  print_timestamp*/
	long long 			tsum2;
	long 				tmin;		/* minimum round trip time */
	long 				tmax;			/* maximum round trip time */
	int 				rtt;
	long 				nchecksum;			/* replies with bad checksum */
	long 				nrepeats;			/* number of duplicates */
	int					isRunning;
//	struct iovec 		iov;
//	struct msghdr		m;
} st_ping_status;


typedef struct ping_configuration{
	int 				icmp_sock;
	struct sockaddr_in 	source;
	struct sockaddr_in  destination;	/* destination */
	int 				preload;
	char*				device;
	char*				url;			/* destination url*/
	int 				broadcast_pings;
	st_connect_msg		cmsg;
	int 				uid;
	int 				euid;
	int 				interval; /* interval between packets (msec) default 1000*/
	int 				pmtudisc;
	int 				datalen;
	int 				optlen;
	unsigned char 		outpack[0x10000];
	char*				hostname;
	int 				options; 
	long 				npackets;
	int 				lingertime;
	int 				rtt_addend;
	int					sndbuf;

	st_ping_status		ping_status;
	
}ping_configuration_packet;

static inline void rcvd_set(__u16 seq)
{
	unsigned bit = seq % MAX_DUP_CHK;
	A(bit) |= B(bit);
}

static inline void rcvd_clear(__u16 seq)
{
	unsigned bit = seq % MAX_DUP_CHK;
	A(bit) &= ~B(bit);
}

static inline bitmap_t rcvd_test(__u16 seq)
{
	unsigned bit = seq % MAX_DUP_CHK;
	return A(bit) & B(bit);
}

void main_loop(ping_configuration_packet* pst_ping_conf, __u8 *packet, 
						int packlen, st_handler_packet* phandler);
void setup(ping_configuration_packet* pst_ping_config);
void sock_setbufs(ping_configuration_packet* pst_ping_config, int alloc);
int modify_capability(int on, uid_t euid);

int do_ping(ping_configuration_packet* pst_ping_config, st_handler_packet* phandler);
int ping_set(ping_configuration_packet* pst_ping_config);

#endif
